package com.flyox.game.militarychess.server.multicastserver;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;

import com.flyox.game.militarychess.CONSTS;

/**
 * ip组播通信依赖于ip组播地址，在 ipv4中它是一个d类ip地址，
 * 范围从224.0.0.0到239.255.255.255，并被划分为局部链接组播地址、预留组播地址和管理权限组播地址三类。
 * 其中，局部链接组播地址范围在224.0.0.0~224.0.0.255，这是为路由协议和其它用途保留的地址，路由器并不转发属于此范围的 ip包；
 * 预留组播地址为224.0.1.0~238.255.255.255，可用于全球范围（如internet）或网络协议； 管理权限组播地址为
 * 239.0.0.0~239.255.255.255，可供组织内部使用，类似于私有ip地址，不能用于internet，可限制组播范围。
 * 
 * IP数据包传输类型
IPv4定义了3种IP数据包的传输：
单播（unicast）
广播（broadcast）
组播（multicast）.
比较一下unicast和multicast两种数据的传输方式可以发现，
当一台主机向多个用户发送信息时，单播对于每一个用户都
要发送一份数据的拷贝，而组播总共只需发送一份数据的拷贝。
这样，组播的使用就大大的节省了带宽，减轻了网络的负载，
从而更加有效的利用了网络的带宽资源.
IP组播和单播的目的地址不同，IP组播的目的地址是组地址.
是从224.0.0.0到239.255.255.255之间的D类IP地址，其中
224.0.0.0到224.0.0.255是被保留的地址,224.0.0.1表示子
网中所有的组播组, 224.0.0.2表示子网中的所有路由器，
224.0.0.5表示OSPF（Open Shortest Path First）路由器,
224.0.0.6表示OSPF指定路由器，224.0.0.12表示DHCP服务器.
在D类地址的分配中，IETF建议遵循以下的原则：
    全球范围：224.0.1.0～238.255.255.255；
    有限范围：239.0.0.0～239.255.255.255；
    本地站点范围：239.253.0.0～239.253.0.16
本地机构范围：239.192.0.0～239.192.0.14.
 */
public class MulticastServer implements Runnable {
	private InetAddress group;
	private MulticastSocket socket;
	public boolean isRun = true;
	private DatagramPacket packet;
	private byte[] data = new byte[512];
	private String ip;

	public MulticastServer() {
		try {
			group = InetAddress.getByName(CONSTS.SYS_CFG_BROAD_GROUP); // 设置组播组的地址为239.0.0.0
			socket = new MulticastSocket(CONSTS.SYS_CFG_BROAD_PORT); // 初始化MulticastSocket类并将端口号与之关联
			//socket.setSoTimeout(100); // 设置组播数据报的发送范围为本地网络
			//socket.setTimeToLive(1); // 设置套接字的接收数据报的最长时间
			socket.joinGroup(group); // 加入组播组
			packet = new DatagramPacket(data, data.length, group, CONSTS.SYS_CFG_BROAD_PORT);

			ip = InetAddress.getLocalHost().getHostAddress();
		} catch (Exception e) {
			System.out.println("Error: " + e); // 捕捉异常情况
		}

	}

	public void run() {
		while (isRun) {
			packet.setData(new byte[15]);
			packet.setLength(15);
			try {
				socket.receive(packet);

				String message = new String(packet.getData(), 0, packet.getLength()).trim();
				if ("hello".equals(message)) {
					packet.setData(ip.getBytes());
					socket.send(packet);
				}
			} catch (IOException e) {
				e.printStackTrace();
			}

		}

	}
}
